﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.Collections.ObjectModel;
using System.IO;
using SharedLib.BasicServices.Plugin.Configuration;
using SharedLib.BasicServices.Plugin;

namespace SharedLib.BasicServices
{
    public class RegisteredObjectService
    {
        //#region Singleton
        ///// <summary>
        ///// Get the singleton instance
        ///// </summary>
        //public static RegisteredObjectService Instance
        //{
        //    get { return SingletonHelper._instance; }
        //}

        ///// <summary>
        ///// Nested helper class
        ///// </summary>
        //internal class SingletonHelper
        //{
        //    static SingletonHelper() { }
        //    internal static readonly RegisteredObjectService _instance = new RegisteredObjectService();
        //}

        //private RegisteredObjectService()
        //{
        //    //Init codes come here
        //    Initialize();
        //}
        //#endregion

        public RegisteredObjectService()
        {
            Initialize();
        }
        private ICollection<Type> _registeredInterfaces = new Collection<Type>();
        /// <summary>
        /// Interfaces of the Registered Classes
        /// </summary>
        protected ICollection<Type> RegisteredInterfaces
        {
            get { return _registeredInterfaces; }
        }

        private IDictionary<string, IDictionary<string, Type>> _registeredClasses = new Dictionary<string, IDictionary<string, Type>>();

        protected IDictionary<string, IDictionary<string, Type>> RegisteredClasses
        {
            get { return _registeredClasses; }
        }

        public void RegisterInterface<T>() where T : IRegisteredObject
        {
            Type t = typeof(T);
            if (!RegisteredInterfaces.Contains(t)) RegisteredInterfaces.Add(t);
        }

        public void RegisterClass(Type typeClass)
        {
            foreach (Type typeInterface in typeClass.GetInterfaces())
            {
                if (RegisteredInterfaces.Contains(typeInterface))
                {
                    IDictionary<string, Type> classesInSpecifiedInterface;
                    string interfaceName = typeInterface.FullName;
                    if (!RegisteredClasses.ContainsKey(interfaceName))
                    {
                        classesInSpecifiedInterface = new Dictionary<string, Type>();
                        RegisteredClasses.Add(interfaceName, classesInSpecifiedInterface);
                    }
                    else
                    {
                        classesInSpecifiedInterface = RegisteredClasses[interfaceName];
                    }
                    classesInSpecifiedInterface.Add(typeClass.FullName, typeClass);
                }
            }
        }

        public void RegisterClass<T>() where T : IRegisteredObject
        {
            Type typeClass = typeof(T);
            RegisterClass(typeClass);
        }

        /// <summary>
        /// Override for customizd initialization operations
        /// </summary>
        protected virtual void Initialize()
        {

        }

        /// <summary>
        /// Create class instance
        /// </summary>
        /// <param name="typeInterface"></param>
        /// <param name="className"></param>
        /// <returns></returns>
        public T CreateInstance<T>(string className) where T : class, IRegisteredObject
        {
            return CreateInstance(typeof(T).FullName, className) as T;
        }

        /// <summary>
        /// Create class instance
        /// </summary>
        /// <param name="interfaceName"></param>
        /// <param name="className"></param>
        /// <returns></returns>
        public IRegisteredObject CreateInstance(string interfaceName, string className)
        {
            if (RegisteredClasses.ContainsKey(interfaceName))
            {
                IDictionary<string, Type> classesInSpecifiedInterface = RegisteredClasses[interfaceName];
                if (classesInSpecifiedInterface.ContainsKey(className))
                {
                    Type typeClass = classesInSpecifiedInterface[className];

                    return (IRegisteredObject)Activator.CreateInstance(typeClass);
                }
            }
            return null;
        }

        public void loadPlugins(PluginManager manager)
        {
            RegisterInterface<IPlugin>();
            foreach (Type t in manager.PluginTypes)
            {
                RegisterClass(t);
            }
        }

    }
}
